---
title: 0.31.0
description: Anchor - Release Notes 0.31.0
---

The last major release before v1 is finally here.

As always, there are a great number of changes, but we'll only be covering the
most important ones here. For a list of all notable changes, see the
[CHANGELOG](https://github.com/coral-xyz/anchor/blob/v0.31.0/CHANGELOG.md#0310---2025-03-08).

---

## How to upgrade

1. Install the latest version of `avm`:

   ```sh
   cargo install --git https://github.com/coral-xyz/anchor avm --force
   ```

   This will allow installing Anchor CLI without having to compile from source,
   see [Install from binary](#install-from-binary).

2. Update `anchor-cli`:

   ```sh
   avm install 0.31.0
   ```

3. Update Anchor crate(s) to `0.31.0`.

4. Update TS package(s) to `0.31.0`.

## Recommended Solana Version

The recommended Solana version is `2.1.0`. This is a special upgrade because
some of the Solana binaries have been renamed to Agave, see
[Agave transition](https://github.com/anza-xyz/agave/wiki/Agave-Transition).

You can install the newer tooling by running:

```
sh -c "$(curl -sSfL https://release.anza.xyz/v2.1.0/install)"
```

This change is handled automatically if you specify `toolchain.solana_version`,
see [Automatic Agave transition](#automatic-agave-transition).

## AVM

### Install from binary

`avm install` now downloads binaries from GitHub by default.

The following build targets are supported:

- `aarch64-apple-darwin`
- `x86_64-unknown-linux-gnu`
- `x86_64-apple-darwin`
- `x86_64-pc-windows-msvc`

You can add the `--from-source` flag to the `install` command if that's
preferred (or required due to unsupported platform).

## CLI

### Automatic Agave transition

As mentioned in [Recommended Solana version](#recommended-solana-version)
section, some of the Solana binaries are renamed to Agave. `solana-install` is
deprecated in `1.18.19` and logs a deprecation message when used (this results
in parsing failure in older Anchor versions):

```
⚠️  solana-install is deprecated and will be discontinued when v1.18 is no longer supported. Please switch to Agave: https://github.com/anza-xyz/agave/wiki/Agave-Transition
```

In this release, if you specify `solana_version` field with a version greater
than `1.18.19`, it automatically installs and switches to `agave-install`:

```toml
[toolchain]
solana_version = "2.1.0"
```

### `solana-program` warning

Adding `solana-program` as a dependency of Anchor programs should be avoided to
decrease the possibility of version conflicts between Solana v1 and v2 crates.

You'll see the following warning on builds if you have `solana-program` in your
dependency list:

```
WARNING: Adding `solana-program` as a separate dependency might cause conflicts.
To solve, remove the `solana-program` dependency and use the exported crate from `anchor-lang`.
`use solana_program` becomes `use anchor_lang::solana_program`.
Program name: `my-program`
```

### Pass `cargo` args to IDL build

Both `anchor build` and `anchor idl build` commands pass the `cargo` arguments
to the underyling IDL build command. For example:

```
anchor build -- --features my-feature
```

now builds the IDL with `my-feature` enabled.

### `--no-idl` flag for tests

If you make a change to your program, but the API of the program stays the same,
building the IDL is pointless and takes additional time.

Similar to [`--no-idl` flag on builds](./0-30-0#--no-idl-flag-on-builds), now
you can use:

```
anchor test --no-idl
```

### `mollusk` test template

You can initialize your workspace using the new
[`mollusk`](/docs/testing/mollusk) template by running:

```sh
anchor init my-program --test-template mollusk
```

### `clean`

`anchor clean` now also removes the generated `.anchor` directory.

For those of you that don't know, this command is similar to `cargo clean`, but
it keeps the program keypairs.

### Automatic IDL conversion

Legacy IDLs (pre Anchor v0.30) were not supported in v0.30, unless you first
converted them to the new spec using `anchor idl convert`. In this release,
various commands do this conversion automatically, meaning you'll be able to
work with both specs without having to switch versions. The only exception is
the `idl fetch` command, which does not convert legacy IDLs.

### Package manager

Anchor has been using `yarn` as the default JS package manager, but some people
want to use other package managers. Changing the package manager to use wasn't
easy, as certain commands required `yarn` to be installed to function properly.
This is no longer the case, and you can simply specify the package manager to
use from `Anchor.toml`:

```toml
[toolchain]
package_manager = "npm"
```

or when creating a new workspace:

```
anchor init <NAME> --package-manager npm
```

Supported values: `npm`, `yarn`, `pnpm` (default: `yarn`)

### Shell completions

You can now generate shell completions, see
[Shell Completions](/docs/installation#shell-completions).

## Lang

### Stack memory improvements

This is going to be a longer section, TL;DR is stack usage is improved massively
when using `init` constraints, and stack warnings on builds are now reliable
when using Solana v2 (`platform-tools v1.42`). Keep reading if you're interested
in learning more, otherwise you can skip to
[Custom discriminators](#custom-discriminators).

The main place where Anchor programs are likely to hit stack violation errors is
a generated function called `try_accounts`. This is where the instruction is
deserialized and constraints are run. Although having everything at the same
place is convenient for using constraints, this also makes it very easy to use
the fixed amount of stack space (4096 bytes) SVM allocates just by increasing
the number of accounts the instruction has. You might be familiar with it from
the mangled build logs:

```
Error: Function _ZN71_$LT$pr..Test$u20$as$u20$anchor_lang..Accounts$LT$pr..TestBumps$GT$$GT$12try_accounts17h5572074d55b9e638E Stack offset of 4112 exceeded max offset of 4096 by 16 bytes, please minimize large stack variables.
```

The problem was made worse with the following external developments:

1. Rust/LLVM changes shipped with Solana v1.18 made Anchor's `try_accounts`
   function use even more stack space, resulting in much lower threshold to hit
   stack-related problems.
2. The stack logs were unreliable, meaning you wouldn't always get warnings
   during builds if you went over the stack limit.
3. The feature
   ["Account data direct mapping"](https://github.com/solana-labs/solana/issues/29708),
   which is enabled by default when using local-validator, made the programs run
   into [undefined behavior](https://en.wikipedia.org/wiki/Undefined_behavior)
   when a function used more stack space than it had available.

All of this combined meant that your programs used more stack space (1), but
sometimes the errors didn't get caught during the compile time (2) or even the
runtime (3).

Undefined behavior is particularly challenging to debug because things may
appear to work as expected during tests, but a different input to the same test
might overwrite an account's data with unintended bytes. There are endless
scenarios that could go wrong here, and some examples include
[#2955](https://github.com/coral-xyz/anchor/issues/2955),
[#3113](https://github.com/coral-xyz/anchor/issues/3113), and
[#3196](https://github.com/coral-xyz/anchor/issues/3196).

There isn't much we can do for problems 1 and 3, but the problem 2 is resolved
with Solana v2 (`platform-tools v1.42`), meaning you'll reliably get warnings
about all stack problems.

Circling back to Anchor, the biggest offender to the stack usage was identified
to be the `init` constraint. Each `init` constraint expands to a lengthy code
inside `try_accounts`, resulting in excessive stack usage when multiple `init`
constraints are used. This problem was fixed by moving the `init` code inside a
closure and immediately calling it in order to create and use a different stack
frame ([#2939](https://github.com/coral-xyz/anchor/pull/2939)).

Related to this topic, there is
[SIMD-0166](https://github.com/solana-foundation/solana-improvement-documents/pull/166),
a proposal to introduce dynamic stack frames.

In short, you'll have fewer problems related to stack memory when using Anchor
v0.31 and Solana v2. If you're still running into problems, please create an
issue in [coral-xyz/anchor](https://github.com/coral-xyz/anchor/issues/3097).

### Custom discriminators

Before this release, there were several problems regarding Anchor
discriminators:

- Due to the transaction size limits enforced by the Solana runtime (1232
  bytes), 8 bytes can be too high for some use cases
- The `Discriminator` trait had a fixed size type field (`[u8; 8]`), which meant
  we wouldn't be able to implement it for non-Anchor programs (e.g. in
  `declare_program!`)
- Discriminators were not customizable
- Changing the name of the data type the discriminator was derived from resulted
  in a different discriminator

This release solves all of the above problems by introducing support for custom
discriminators. The default 8-byte discriminators have not changed, but you can
override them via the `discriminator` argument implemented in various Anchor
attribute macros:

- `#[account(discriminator = 1)]`
- `#[event(discriminator = [1, 2])]`
- `#[instruction(discriminator = MY_CONST)]`

All constant expressions are supported.

See
[example](https://github.com/coral-xyz/anchor/blob/v0.31.0/tests/custom-discriminator/programs/custom-discriminator/src/lib.rs).

It's important that the discriminator is always unique for the type you're
implementing it for. While the discriminator can be at any length (including
zero), the IDL generation does not currently allow empty discriminators for
safety and convenience reasons. However, the `Discriminator` trait definition
still allows empty discriminators because some non-Anchor programs, e.g. the SPL
Token program, don't have account discriminators. In that case, safety checks
should never depend on the discriminator.

Additionally, the IDL generation step also checks whether you have ambigious
discriminators i.e. discriminators that can be used for multiple types. However,
you should still consider future possibilities, especially when working with
1-byte discriminators. For example, having an account with discriminator `[1]`
means you can't have any other discriminators that start with `1`, e.g.
`[1, 2 , 3, 4]`, as it would not be unique.

This change also enables using non-Anchor programs with both Rust (via
[`declare_program!`](./0-30-0#dependency-free-program-declaration)) and in the
TS client.

### `Discriminator` trait

The `discriminator` method of the `Discriminator` trait has been removed. If you
have compilation errors related to this removal, you can simply replace the
`discriminator()` call to the `DISCRIMINATOR` associated constant.

This trait is now exported from `prelude`, and it can be used to replace a very
common usage that hardcodes the discriminator length as `8`. For example, the
following:

```rs
space = 8 + ...
```

can be replaced by:

```rs
space = MyAccount::DISCRIMINATOR.len() + ...
```

### `LazyAccount`

`LazyAccount` is an experimental account type that can be used to replace
`Account` when you're running into performance-related problems.

We'll skip the details to keep the release notes as short as possible, but if
you're interested, check out
[its documentation](https://docs.rs/anchor-lang/0.31.0/anchor_lang/accounts/lazy_account/struct.LazyAccount.html)
to see if it fits your needs.

**Note:** You need to enable `lazy-account` feature of `anchor-lang` to be able
to use `LazyAccount`.

### `cfg` attribute on instructions

You can now use `cfg` attributes on instructions:

```rs
#[program]
mod my_program {
    #[cfg(feature = "my-feature")]
    pub fn my_feature(ctx: Context<MyFeature>) -> Result<()> {}
}
```

### Unnamed and unit structs with `InitSpace`

Unnamed and unit struct support was added in v0.30, but deriving `InitSpace` did
not work with these structs. This release adds support for both of them:

```rs
#[derive(InitSpace)]
pub struct Unnamed(pub u64, #[max_len(64)] pub Vec<u8>);

#[derive(InitSpace)]
pub struct Unit;
```

### Account parser

You can now conveniently parse any program account using `declare_program!`:

```rs
declare_program!(my_program);
```

This will generate something similar to:

```rs
pub enum Account {
    SomeAccount(SomeAccount),
    OtherAccount(OtherAccount),
}
```

Use `my_program::utils::Account::try_from_bytes` to parse any account belonging
to the program.

### `declare_program!` improvements

The following issues related to
[`declare_program!`](/docs/features/declare-program) have been fixed:

- Being unable to use constant bytes
  ([#3287](https://github.com/coral-xyz/anchor/pull/3287))
- Missing docs from the generated constants
  ([#3311](https://github.com/coral-xyz/anchor/pull/3311))
- Compilation errors related to incorrectly adding `derive`s and `repr`s to type
  aliases ([#3504](https://github.com/coral-xyz/anchor/pull/3504))
- Being unable to use `data` as an instruction parameter
  ([#3574](https://github.com/coral-xyz/anchor/pull/3574))

## SPL

### New Token 2022 instructions

The following Token 2022 instructions were added:

- `burn_checked`
- `mint_to_checked`
- `approve_checked`
- `withdraw_withheld_tokens_from_accounts`

## IDL

### Safety comment checks

In v0.30.1, you'd run into panics in Rust Analyzer if you enabled all features
because the `idl-build` feature expected an environment variable to be set. This
was always set if you used `anchor build`, but since Rust Analyzer did not know
about this environment variable, it would panic:

```
custom attribute panicked
message: Safety checks failed: Failed to get program path
```

It no longer panics if the environment variable is missing.

### `address` constraint with non-const expressions

There was a regression in v0.30 that made using non-const expressions with the
`address` constraint fail:

```rs
#[derive(Accounts)]
pub struct MyIx {
    #[account(address = my_account.authority())]
    pub authority: Signer<'info>,
    pub my_account: Account<'info, MyAccount>,
}
```

This is now fixed and no longer results in build errors.

See [coral-xyz/anchor#3216](https://github.com/coral-xyz/anchor/pull/3216) for
more information.

### `Program` accounts with full paths

The following did not work in v0.30, but it works now:

```rs
#[derive(Accounts)]
pub struct FullPath<'info> {
    pub external_program: Program<'info, external::program::External>,
}
```

### `IdlBuilder`

Building the IDL via the
[`build_idl`](https://github.com/coral-xyz/anchor/blob/v0.31.0/idl/src/build.rs#L119)
function made it impossible to extend its functionality e.g. add new parameters
without a breaking change. To solve this problem, there is a new way to build
IDLs programatically:

```rs
let idl = IdlBuilder::new().program_path(path).skip_lint(true).build()?;
```

See
[`IdlBuilder`](https://docs.rs/anchor-lang-idl/0.1.2/anchor_lang_idl/build/struct.IdlBuilder.html)
for more information.

### Generation improvements

The following issues with the IDL generation have been fixed:

- A bug where using tuple parameters in instructions would result in an
  incorrect IDL ([#3294](https://github.com/coral-xyz/anchor/pull/3294))
- A bug where doc comments could trigger false-positives during module paths
  convertion ([#3359](https://github.com/coral-xyz/anchor/pull/3359))
- A bug where the generated IDL only has partial resolution information
  ([#3474](https://github.com/coral-xyz/anchor/pull/3474))
- Being unable to use constant identifiers as generic arguments
  ([#3522](https://github.com/coral-xyz/anchor/pull/3522))
- Being unable to pass in a `Pubkey` constant to `seeds::program`
  ([#3559](https://github.com/coral-xyz/anchor/pull/3559))
- Being unable to pass in an account or an argument to `seeds::program`
  ([#3570](https://github.com/coral-xyz/anchor/pull/3570))

## TypeScript

### Simpler `Program` construction

TypeScript's automatic inference of JSON files made it difficult to use the
`Program` constructor without additional casting:

```ts
import * as idl from "./idl/my_program.json";
import type { MyProgram } from "./types/my_program";

const program = new Program(idl as unknown as MyProgram, provider);
```

Casting to `unknown` or `any` was necessary when TypeScript automatically
inferred the type of the JSON file.

In this release, the program constructor no longer infers the IDL type from the
given `idl` argument. This makes it easier to specify the actual IDL type:

```ts
const program = new Program<MyProgram>(idl, provider);
```

### Error improvements

Account resolution error now includes the accounts that weren't able to get
resolved:

```
Reached maximum depth for account resolution. Unresolved accounts: `pda`, `anotherPda`
```

Similarly, unsupported `view` method error now includes the possible causes:

```
Error: Method does not support views. The instruction should return a value, and its accounts must be read-only
```

### Type improvements

It's common to use `//@ts-ignore` to get the payer keypair in tests:

```ts
// @ts-ignore
const payer = program.provider.wallet.payer;
```

To fix this problem, the `Provider` interface now includes an optional
`wallet: Wallet` field, and similarly, the `Wallet` interface now includes
optional `payer: Keypair` field.

You can now do:

```ts
const payer = program.provider.wallet!.payer!;
```

We're using `!` because we know these fields are going to be defined in our
testing environment.

### Better confirmation

`Provider.sendAndConfirm` now takes in an optional `blockhash` and uses that for
better transaction confirmation:

```ts
await program.provider.sendAndConfirm(tx, signers, { blockhash: ... });
```

### Programs with numbers in their name

Testing programs with numbers in their name using `anchor.workspace` now works
for all cases.

For more details about the problem and its solution, see
[#3450](https://github.com/coral-xyz/anchor/pull/3450).

## Rust Client

### `tokio` support

There was a problem that made it impossible to use `tokio` with
[`anchor-client`](https://docs.rs/anchor-client/0.31.0/anchor_client/index.html).
This problem is now fixed, and you can use `tokio` (with `async` feature). See
[`tokio` example](https://github.com/coral-xyz/anchor/blob/v0.31.0/client/example/src/nonblocking.rs#L65-L99).

### Mock client

It's now possible to pass in a
[mock RPC client](https://docs.rs/solana-client/2.1.0/solana_client/rpc_client/struct.RpcClient.html#method.new_mock)
for testing by enabling the `mock` feature:

```toml
anchor-client = { version = "0.31.0", features = ["mock"] }
```

---

See the full list of notable changes in the
[CHANGELOG](https://github.com/coral-xyz/anchor/blob/v0.31.0/CHANGELOG.md#0310---2025-03-08).
